
from saas.const import *
from saas.handler import *
from saas.log import *
from saas.pkt import *
from socket import *
import sys


ipv4_sock = None
ipv6_sock = None


def listen( inst ):
	## try to start the IPv4 listener first. if there's an error starting it, move on
	## but record that IPv4 has been disabled.
	if inst.conf.use_ipv4 == 1:
		logm( LOG_DEBUG , 'Attempting to bind (IPv4) to %s:%d' % ( inst.conf.ipv4_bind_addr , inst.conf.port ) )
		try:
			ipv4_sock = socket( AF_INET , SOCK_DGRAM )
			ipv4_sock.bind( ( inst.conf.ipv4_bind_addr , inst.conf.port ) )
			logm( LOG_DEBUG , 'Successfully opened IPv4 socket.' )
		except:
			logm( LOG_WARNING , 'Could not bind to IPv4 address %s:%d! Disabling IPv4 functionality and continuing initialisation.' % ( inst.conf.ipv4_bind_addr , inst.conf.port ) )
			inst.conf.use_ipv4 = 0
	else:
		logm( LOG_DEBUG , 'Not starting IPv4 listener (as requested in saasd.conf)' );

	## now we try to initialise IPv6. same deal as before -- if there's an error, skip it
	## and record that IPv6 is disabled.
	if inst.conf.use_ipv6 == 1:
		logm( LOG_DEBUG , 'Attempting to bind (IPv6) to [%s]:%d' % ( inst.conf.ipv6_bind_addr , inst.conf.port ) )
		try:
			ipv6_sock = socket( AF_INET6 , SOCK_DGRAM )
			ipv6_sock.bind( ( inst.conf.ipv6_bind_addr , inst.conf.port ) )
			logm( LOG_DEBUG , 'Successfully opened IPv6 socket.' )
		except:
			logm( LOG_WARNING , 'Could not bind to IPv6 address [%s]:%d! Disabling IPv6 functionality and continuing initialisation.' % ( inst.conf.ipv6_bind_addr , inst.conf.port ) )
			inst.conf.use_ipv6 = 0
	else:
		logm( LOG_DEBUG , 'Not starting IPv6 listener (as requested in saasd.conf)' );


	## now we check to ensure that at least one of them started.
	if inst.conf.use_ipv4 == 0 and inst.conf.use_ipv6 == 0:
		logm( LOG_ERR , 'No socket listeners were successfully started. SAAS Daemon is exiting.' );
		return False


	while inst.conf.use_ipv4 == 1 or inst.conf.use_ipv4 == 1:
		## attempt to read a packet from the socket.
		try:
			data,sender = ipv4_sock.recvfrom( SAAS_MAX_PKT_LEN )
		except KeyboardInterrupt:
			break

		response = handle_packet( inst , data , sender )

		if response != None and response != False:
			logm( LOG_DEBUG , 'transmitting response to %s:%d' % sender )
			ipv4_sock.sendto( response , sender )
		else:
			logm( LOG_WARNING , 'not transmitting response to %s:%d due to errors with request or creating response' % sender )

	if inst.conf.use_ipv4:
		ipv4_sock.close()
	if inst.conf.use_ipv6:
		ipv6_sock.close()

	return True


def handle_packet( inst , data , sender ):
	## try to decrypt the packet.
	pkt = pkt_decrypt( data , inst.conf )
	if pkt == None:
		logm( LOG_WARNING , 'error decrypting packet from: %s:%d' % sender )
		return None


	## pull apart the packet.
	parts = pkt_unpack( pkt )
	if parts == None or parts == False:
		logm( LOG_WARNING , 'received malformed packet from: %s:%d' % sender )
		return None
	( trans_id , pkttype , payload_len , payload ) = parts


	## now we pass the packet off to the packet-type-specific handlers.
	if pkttype == SAAS_PKT_TYPE_PING:
		logm( LOG_DEBUG , 'received PING packet from %s:%d' % sender )
		payload = handle_ping( inst , payload )

	if pkttype == SAAS_PKT_TYPE_AUTHENTICATE:
		logm( LOG_DEBUG , 'received AUTHENTICATE packet from %s:%d' % sender )
		payload = handle_authenticate( inst , payload )

	if pkttype == SAAS_PKT_TYPE_CHANGE_PASSWORD:
		logm( LOG_DEBUG , 'received CHANGE PASSWORD packet from %s:%d' % sender )
		payload = handle_change_password( inst , payload )


	if pkttype == SAAS_PKT_TYPE_UID_TO_USERNAME:
		logm( LOG_DEBUG , 'received UID TO USERNAME packet from %s:%d' % sender )
		payload = handle_uid_to_username( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USERNAME_TO_UID:
		logm( LOG_DEBUG , 'received USERNAME TO UID packet from %s:%d' % sender )
		payload = handle_username_to_uid( inst , payload )


	if pkttype == SAAS_PKT_TYPE_GID_TO_GROUPNAME:
		logm( LOG_DEBUG , 'received GID TO GROUPNAME packet from %s:%d' % sender )
		payload = handle_gid_to_groupname( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUPNAME_TO_GID:
		logm( LOG_DEBUG , 'received GROUPNAME TO GID packet from %s:%d' % sender )
		payload = handle_groupname_to_gid( inst , payload )


	if pkttype == SAAS_PKT_TYPE_USER_INFO_BY_UID:
		logm( LOG_DEBUG , 'received USER INFO BY UID packet from %s:%d' % sender )
		payload = handle_user_info_by_uid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USER_INFO_BY_USERNAME:
		logm( LOG_DEBUG , 'received USER INFO BY USERNAME packet from %s:%d' % sender )
		payload = handle_user_info_by_username( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USER_INFO_WITH_GROUPS_BY_UID:
		logm( LOG_DEBUG , 'received USER INFO WITH GROUPS BY UID packet from %s:%d' % sender )
		payload = handle_user_info_with_groups_by_uid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USER_INFO_WITH_GROUPS_BY_USERNAME:
		logm( LOG_DEBUG , 'received USER INFO WITH GROUPS BY USERNAME packet from %s:%d' % sender )
		payload = handle_user_info_with_groups_by_username( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USER_INFO_WITH_ALL_GROUPS_BY_UID:
		logm( LOG_DEBUG , 'received USER INFO WITH ALL GROUPS BY UID packet from %s:%d' % sender )
		payload = handle_user_info_with_all_groups_by_uid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_USER_INFO_WITH_ALL_GROUPS_BY_USERNAME:
		logm( LOG_DEBUG , 'received USER INFO WITH ALL GROUPS BY USERNAME packet from %s:%d' % sender )
		payload = handle_user_info_with_all_groups_by_username( inst , payload )


	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_BY_GID:
		logm( LOG_DEBUG , 'received GROUP INFO BY GID packet from %s:%d' % sender )
		payload = handle_group_info_by_gid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_BY_GROUPNAME:
		logm( LOG_DEBUG , 'received GROUP INFO BY GROUPNAME packet from %s:%d' % sender )
		payload = handle_group_info_by_groupname( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GID:
		logm( LOG_DEBUG , 'received GROUP INFO WITH MEMBERS BY GID packet from %s:%d' % sender )
		payload = handle_group_info_with_members_by_gid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_WITH_MEMBERS_BY_GROUPNAME:
		logm( LOG_DEBUG , 'received GROUP INFO WITH MEMBERS BY GROUPNAME packet from %s:%d' % sender )
		payload = handle_group_info_with_members_by_groupname( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GID:
		logm( LOG_DEBUG , 'received GROUP INFO WITH ALL MEMBERS BY GID packet from %s:%d' % sender )
		payload = handle_group_info_with_all_members_by_gid( inst , payload )

	if pkttype == SAAS_PKT_TYPE_GROUP_INFO_WITH_ALL_MEMBERS_BY_GROUPNAME:
		logm( LOG_DEBUG , 'received GROUP INFO WITH ALL MEMBERS BY GROUPNAME packet from %s:%d' % sender )
		payload = handle_group_info_with_all_members_by_groupname( inst , payload )


	if payload == False or payload == None:
		logm( LOG_WARNING , 'packet-specific handler did not return successfully' )
	else:
		if len( payload ) > 0:
			## pack a packet header top of the payload
			pkt = pkt_pack( trans_id , pkttype , payload )
			logm( LOG_DEBUG , 'about to encrypt and transmit response of %d bytes' % len( pkt ) )
			return pkt_encrypt( pkt , inst.conf )
		else:
			logm( LOG_WARNING , 'packet-specific handler did not return successfully' )

	return None




